package org.cybzacg.convert.matcher;


import org.cybzacg.convert.context.ConversionContext;
import org.cybzacg.convert.core.TypeConverter;
import org.cybzacg.convert.enums.ConversionError;
import org.cybzacg.convert.enums.ConversionPriority;
import org.cybzacg.convert.enums.SelectionStrategy;
import org.cybzacg.convert.exception.ConversionException;

import java.util.List;

/**
 * 转换器选择器 - 智能选择最佳转换器
 * 基于匹配度、优先级和上下文信息选择最合适的转换器
 *
 * @author cybzacg.blog
 * @version 3.1
 * @since 3.1
 */
public class ConverterSelector {

    private final ConversionMatcher matcher;
    private SelectionStrategy strategy;


    /**
     * 构造函数
     */
    public ConverterSelector() {
        this(new ConversionMatcher(), SelectionStrategy.BEST_MATCH);
    }

    /**
     * 构造函数
     *
     * @param strategy 选择策略
     */
    public ConverterSelector(SelectionStrategy strategy) {
        this(new ConversionMatcher(), strategy);
    }

    /**
     * 构造函数
     *
     * @param matcher  匹配器
     * @param strategy 选择策略
     */
    public ConverterSelector(ConversionMatcher matcher, SelectionStrategy strategy) {
        this.matcher = matcher;
        this.strategy = strategy;
    }

    /**
     * 选择最佳转换器
     *
     * @param converters 候选转换器列表
     * @param sourceType 源类型
     * @param targetType 目标类型
     * @param context    转换上下文
     * @return 选择结果
     * @throws ConversionException 如果没有找到合适的转换器
     */
    public SelectionResult selectConverter(List<TypeConverter> converters,
                                           Class<?> sourceType,
                                           Class<?> targetType,
                                           ConversionContext context) throws ConversionException {
        long startTime = System.currentTimeMillis();

        // 获取匹配结果
        List<MatchResult> matchResults =
                matcher.matchConverters(converters, sourceType, targetType, context);

        if (matchResults.isEmpty()) {
            throw new ConversionException(
                    ConversionError.UNSUPPORTED_CONVERSION,
                    String.format("No converter found for %s -> %s",
                            sourceType != null ? sourceType.getSimpleName() : "null",
                            targetType != null ? targetType.getSimpleName() : "null")
            );
        }

        // 根据策略选择转换器
        MatchResult selectedMatch = selectByStrategy(matchResults, strategy);

        long selectionTime = System.currentTimeMillis() - startTime;
        String selectionReason = generateSelectionReason(selectedMatch, matchResults, strategy);

        return new SelectionResult(selectedMatch.getConverter(), selectedMatch, selectionReason, selectionTime);
    }

    /**
     * 选择最佳转换器（简化版本）
     *
     * @param converters 候选转换器列表
     * @param sourceType 源类型
     * @param targetType 目标类型
     * @return 选择结果
     * @throws ConversionException 如果没有找到合适的转换器
     */
    public SelectionResult selectConverter(List<TypeConverter> converters,
                                           Class<?> sourceType,
                                           Class<?> targetType) throws ConversionException {
        return selectConverter(converters, sourceType, targetType, null);
    }

    /**
     * 根据策略选择转换器
     */
    private MatchResult selectByStrategy(
            List<MatchResult> matchResults,
            SelectionStrategy strategy) {

        return switch (strategy) {
            case BEST_MATCH -> selectBestMatch(matchResults);
            case PRIORITY_FIRST -> selectByPriority(matchResults);
            case BALANCED -> selectBalanced(matchResults);
            case FAST -> selectFirst(matchResults);
            default -> selectBestMatch(matchResults);
        };
    }

    /**
     * 最佳匹配策略 - 选择匹配度最高的转换器
     */
    private MatchResult selectBestMatch(List<MatchResult> matchResults) {
        return matchResults.get(0); // 已经按匹配度排序
    }

    /**
     * 优先级优先策略 - 优先选择高优先级的转换器
     */
    private MatchResult selectByPriority(List<MatchResult> matchResults) {
        return matchResults.stream()
                .min((a, b) -> a.getPriority().comparePriority(b.getPriority()))
                .orElse(matchResults.get(0));
    }

    /**
     * 平衡策略 - 平衡匹配度和优先级
     */
    private MatchResult selectBalanced(List<MatchResult> matchResults) {
        return matchResults.stream()
                .max((a, b) -> {
                    // 计算综合分数：匹配度 * 0.6 + 优先级权重 * 0.4
                    double scoreA = a.getMatchScore() * 0.6 + getPriorityWeight(a.getPriority()) * 0.4;
                    double scoreB = b.getMatchScore() * 0.6 + getPriorityWeight(b.getPriority()) * 0.4;
                    return Double.compare(scoreA, scoreB);
                })
                .orElse(matchResults.get(0));
    }

    /**
     * 快速策略 - 选择第一个可用的转换器
     */
    private MatchResult selectFirst(List<MatchResult> matchResults) {
        return matchResults.get(0);
    }

    /**
     * 获取优先级权重
     */
    private double getPriorityWeight(ConversionPriority priority) {
        switch (priority.getGroup()) {
            case SYSTEM:
                return 1.0;
            case HIGH:
                return 0.8;
            case MEDIUM:
                return 0.6;
            case LOW:
                return 0.4;
            default:
                return 0.2;
        }
    }

    /**
     * 生成选择原因
     */
    private String generateSelectionReason(MatchResult selectedMatch,
                                           List<MatchResult> allMatches,
                                           SelectionStrategy strategy) {
        StringBuilder reason = new StringBuilder();

        reason.append("策略: ").append(strategy.name());
        reason.append(", 匹配度: ").append(String.format("%.2f", selectedMatch.getMatchScore()));
        reason.append(", 优先级: ").append(selectedMatch.getPriority().getName());

        if (allMatches.size() > 1) {
            reason.append(String.format(" (从%d个候选中选择)", allMatches.size()));
        }

        return reason.toString();
    }

    /**
     * 检查是否有可用的转换器
     *
     * @param converters 转换器列表
     * @param sourceType 源类型
     * @param targetType 目标类型
     * @param context    转换上下文
     * @return 如果有可用转换器返回true
     */
    public boolean hasAvailableConverter(List<TypeConverter> converters,
                                         Class<?> sourceType,
                                         Class<?> targetType,
                                         ConversionContext context) {
        List<MatchResult> matchResults =
                matcher.matchConverters(converters, sourceType, targetType, context);
        return !matchResults.isEmpty();
    }

    /**
     * 获取所有可用的转换器信息
     *
     * @param converters 转换器列表
     * @param sourceType 源类型
     * @param targetType 目标类型
     * @param context    转换上下文
     * @return 匹配结果列表
     */
    public List<MatchResult> getAvailableConverters(
            List<TypeConverter> converters,
            Class<?> sourceType,
            Class<?> targetType,
            ConversionContext context) {
        return matcher.matchConverters(converters, sourceType, targetType, context);
    }

    /**
     * 设置选择策略
     *
     * @param strategy 选择策略
     */
    public void setStrategy(SelectionStrategy strategy) {
        this.strategy = strategy;
    }

    /**
     * 获取当前选择策略
     *
     * @return 选择策略
     */
    public SelectionStrategy getStrategy() {
        return strategy;
    }

    /**
     * 获取匹配器
     *
     * @return 匹配器
     */
    public ConversionMatcher getMatcher() {
        return matcher;
    }
}
